package com.stm.framework.shiro.realm;

import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.stm.common.exception.user.CaptchaException;
import com.stm.common.exception.user.RoleBlockedException;
import com.stm.common.exception.user.UserBlockedException;
import com.stm.common.exception.user.UserNotExistsException;
import com.stm.common.exception.user.UserPasswordNotMatchException;
import com.stm.common.exception.user.UserPasswordRetryLimitExceedException;
import com.stm.framework.shiro.service.CustomToken;
import com.stm.framework.shiro.service.LoginType;
import com.stm.framework.shiro.service.SysLoginService;
import com.stm.framework.util.ShiroUtils;
import com.stm.system.domain.SysUser;
import com.stm.system.mapper.SysUserMapper;
import com.stm.system.service.ISysMenuService;
import com.stm.system.service.ISysRoleService;

/**
 * 自定义Realm 处理登录 权限
 * 
 * @author admin
 */
public class UserRealm extends AuthorizingRealm
{
    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private SysLoginService loginService;
    
    @Autowired
	SysUserMapper userMapper;

    private AuthenticationInfo info = null;
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
    {
        SysUser user = ShiroUtils.getSysUser();
        // 角色列表
        Set<String> roles = new HashSet<String>();
        // 功能列表
        Set<String> menus = new HashSet<String>();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 管理员拥有所有权限
        if (user.isAdmin())
        {
            info.addRole("admin");
            info.addStringPermission("*:*:*");
        }
        else
        {
            roles = roleService.selectRoleKeys(user.getUserId());
            menus = menuService.selectPermsByUserId(user.getUserId());
            // 角色加入AuthorizationInfo认证对象
            info.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            info.setStringPermissions(menus);
        }
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
    {
     	 // 将token装换成UsernamePasswordToken
        /*UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;*/
        CustomToken upToken = (CustomToken) token;
        // 获取用户名即可
        String username = upToken.getUsername();
        String password = "";
	        if (upToken.getPassword() != null)
	        {
	            password = new String(upToken.getPassword());
	        }
	
	        // 获取用户名即可
	        LoginType type = upToken.getType();
	        if(type.equals(LoginType.PASSWORD)){
	        	SysUser user = null;
	            try
	            {
	                user = loginService.login(username, password);
	            }
	            catch (CaptchaException e)
	            {
	                throw new AuthenticationException(e.getMessage(), e);
	            }
	            catch (UserNotExistsException e)
	            {
	                throw new UnknownAccountException(e.getMessage(), e);
	            }
	            catch (UserPasswordNotMatchException e)
	            {
	                throw new IncorrectCredentialsException(e.getMessage(), e);
	            }
	            catch (UserPasswordRetryLimitExceedException e)
	            {
	                throw new ExcessiveAttemptsException(e.getMessage(), e);
	            }
	            catch (UserBlockedException e)
	            {
	                throw new LockedAccountException(e.getMessage(), e);
	            }
	            catch (RoleBlockedException e)
	            {
	                throw new LockedAccountException(e.getMessage(), e);
	            }
	            catch (Exception e)
	            {
	//                log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
	                throw new AuthenticationException(e.getMessage(), e);
	            }
	            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
	            return info;
	        }
	        	
        	// 查询数据库，是否查询到用户名和密码的用户
        	SysUser userInfo = userMapper.selectUserByLoginName(username);
        	if(userInfo != null) {
    		// 如果查询到了，封装查询结果，返回给我们的调用
    		Object principal =  userInfo;
    		Object credentials = userInfo.getPassword();
    		// 将账户名，密码，盐值，realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
    		info =  new SimpleAuthenticationInfo(principal, credentials, getName());
        
        }else {
            return null;
        }
        return info;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo()
    {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}
